本篇我们主要针对HAL1.0介绍Camera提供的服务,分析Camera打开过程。
打开过程
这里我们看下CameraService的connect。
1 | //最终打开摄像头会调用Service的connect |
客户端在打开摄像头时最终会调用到这个方法,并未其创建了CameraClient对象,这里针对API为1.0时介绍,所以重点关注CameraClient的创建过程及初始化流程,看看它是如何提供摄像头的服务的。在创建完client对象后,在connectFinishUnsafe会对其进行初始化,即调用client->initialize(mModule)方法这个mModule即是底层的Camera模块,其初始化是在CameraService的onFirstRef中
1 | void CameraService::onFirstRef() |
initialize这个方法比较重要,它主要做了下面几件事:
-
创建CameraHardwareInterface对象,CameraHardwareInterface是HAL层的接口对象,CameraClient的所提供的服务最终会转向这个接口对象。在HAL1.0中,这个对象是同HAL层进行交互的桥梁。
-
初始化该接口对象,包括打开摄像头模块 初始化预览窗口回调等
-
调用setCallbacks来设置回调,比如数据的回调,通知消息的回调,这些回调方法都是在CameraClient中实现,即底层会将相关的消息或者数据通过这些方法回调给上层。
我们看看CameraHardwareInterface初始化过程
1 | status_t initialize(hw_module_t *module) |
这个方法纯粹只是打开了HAL module的open方法,会调用底层驱动的打开方法,这个方法会返回一个mDevice,这个mDevice是HAL层定义的camera_device_t结构
1 | typedef struct camera_device { |
camera_device_ops_t是摄像头定义的一系列服务接口,如int (*take_picture)(struct camera_device *);
CameraHardwareInterface层向上提供的服务都是通过HAL层的这些接口完成。
接着初始化HAL的预览窗口
1 | void initHalPreviewWindow() |
这个mHalPreviewWindow是个camera_preview_window,它的定义如下
1 | struct camera_preview_window { |
这里的preview_stream_ops它是一系列关于本地窗口ANativeWindow的操作方法的接口。
回调的设置是通过setCallbacks完成
1 | /** Set the notification and data callbacks */ |
参数notify_cb,data_cb是CameraClient的方法,这里首先对其进行了保存,并将CameraHardwareInterface自身的的__notify_cb,__data_cb等通过HAL层设置给底层驱动,这么说当数据或者消息需要通知到上层时在CameraHardwareInterface的__notify_cb,__data_cb方法是需要再转发给CameraClient的notify_cb和data_cb的。
HAL层的实现,我们这里看的是rk29的相关实现
/android4.4/hardware/rk29/camera/CameraHal_Module.cpp
这个文件中定义了HAL层的module,即HAL_MODULE_INFO_SYM,这是所有HAL层必须定义的。所有的硬件对应的module结构必须以
hw_module_t作为其第一个成员,一般就是common成员。
1 | static struct hw_module_methods_t camera_module_methods = { |
我们看到open方法调用的是camera_device_open,我们看看这个方法
1 | int camera_device_open(const hw_module_t* module, const char* name, |
这个方法主要做下面几件事:
- 创建一个rk_camera_device_t 用来描述Camera设备,它的定义是只是比camera_device_t多了一个cameraid,是对camera_device_t的拓展。
1 | typedef struct rk_camera_device { |
-
创建camera_device_ops_t 用来描述Camera驱动提供的服务方法,在这里对其进行初始化,即指定了HAL层提供服务的具体方法。我们知道camera_device_ops_t是保存在camera_device_t结构中的。
-
创建android::CameraHal对象,这个对象通过和摄像头驱动的交互来提供具体的服务,比如预览,拍照。
预览数据的传递
下面为了进一步熟悉这个流程,我们看看摄像头的预览数据是如何在整个系统中进行传递的。
java层调用setPreviewCallback设置预览回调PreviewCallback,将其保存在mPreviewCallback中,接着调用jni层的
setHasPreviewCallback,即android_hardware_Camera_setHasPreviewCallback
1 | //设置预览回调 |
可以看到这个方法并没有做什么处理,只是通过JNICameraContext 的setCallbackMode给Camera设置了一个回调标记mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER);那么我们无法继续自顶向下进行分析,只能从底层进行分析。我们直接看底层CameraHal层预览相关的,在CameraHal::displayThread的实现中,当取到消息CMD_DISPLAY_FRAME会进行数据帧的绘制显示,这里面会调用由CameraHal::setCallbacks设置的回调mDataCb,它是这样调用的mDataCb(CAMERA_MSG_PREVIEW_FRAME, mPreviewMemory, queue_display_index,NULL,mCallbackCookie);//预览回调 回调给上层 显示了一帧数据这里的mCallbackCookie为上层CameraHardwareInterface对象,这里的消息类型为CAMERA_MSG_PREVIEW_FRAME。
还记得这个回调是在哪里进行设置的? 没错,是在CameraHardwareInterface中,即它的__data_cb方法我们看看这个方法
1 | static void __data_cb(int32_t msg_type, |
这个方法最后通过mDataCb调用给CameraClient::dataCallback
1 | void CameraClient::dataCallback(int32_t msgType, |
当消息类型为CAMERA_MSG_PREVIEW_FRAME时调用clinet的handlePreviewData方法
1 | // preview callback - frame buffer update |
这里的mRemoteCallback是什么呢?是在哪里进行初始化的呢?它是在CameraService::connect时创建CameraClient对象时传递过来的,CameraClient在继承自CameraService::Client,创建该对象会同时构造CameraService::Client,
1 | CameraClient::CameraClient(const sp<CameraService>& cameraService, |
这里的sp
所以继承了BnCameraClient,后者又继承了ICameraClient,它也是一个binder对象。CameraService::Client对将连接的对象保存在其mRemoteCallback中作为回调。
知道了mRemoteCallback怎么来的,那么我们继续看handlePreviewData,在设置预览时我们设置了flag为
预览的回调的flag 之前设置的为CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER,它默认是CAMERA_FRAME_CALLBACK_FLAG_NOOP即禁止回调的。所以最终是通过 c->dataCallback(msgType, mem, metadata)回调给Bp端的,即Camera::dataCallback
1 | // callback from camera service when frame or image is ready |
这里的mListener是谁?调用到哪里去了?它是一个CameraListener类型的接口,原来在JNI层建立摄像头连接的时候会调用camera->setListener(context);这个listener即JNICameraContext,它是继承自CameraListener的。这么说postData应该是JNI层的,我们看看
1 | void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr, |
msgType 是CAMERA_MSG_PREVIEW_FRAME,所以最终调用copyAndPost(env, dataPtr, dataMsgType);
1 | void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType) |
最终是调用CallStaticVoidMethod将数据送到java层的 fields.post_event注册为
1 | fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", |
最终是通过EventHandler来进行的,这里的mEventHandler是在构造Java层的Camera时创建的,我们直接看其对消息的处理
private class EventHandler extends Handler
{
private Camera mCamera;
public EventHandler(Camera c, Looper looper) {
super(looper);
mCamera = c;
}
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
....
case CAMERA_MSG_PREVIEW_FRAME:
PreviewCallback pCb = mPreviewCallback;
if (pCb != null) {
if (mOneShot) {
// Clear the callback variable before the callback
// in case the app calls setPreviewCallback from
// the callback function
mPreviewCallback = null;
} else if (!mWithBuffer) {
// We're faking the camera preview mode to prevent
// the app from being flooded with preview frames.
// Set to oneshot mode again.
setHasPreviewCallback(true, false);
}
pCb.onPreviewFrame((byte[])msg.obj, mCamera);//会通过这里回调给上层应用
}
return;
case CAMERA_MSG_POSTVIEW_FRAME:
if (mPostviewCallback != null) {
mPostviewCallback.onPictureTaken((byte[])msg.obj, mCamera);
}
return;
......
}
}
}
看到对CAMERA_MSG_PREVIEW_FRAME消息的处理,这个mPreviewCallback是我们设置的预览回调,最终调用onPreviewFrame回调给应用。